package com.a01_2021.thousandstimes.general.service.impl;

import com.a01_2021.thousandstimes.exception.CustomException;
import com.a01_2021.thousandstimes.exception.CustomExceptionType;
import com.a01_2021.thousandstimes.general.entity.SysUser;
import com.a01_2021.thousandstimes.general.entity.SysUserRole;
import com.a01_2021.thousandstimes.general.mapper.*;
import com.a01_2021.thousandstimes.general.service.SysRoleService;
import com.a01_2021.thousandstimes.general.service.SysUserService;
import com.a01_2021.thousandstimes.saas.service.IUserMappingService;
import com.a01_2021.thousandstimes.utils.AjaxResponse;
import com.a01_2021.thousandstimes.utils.IO;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author FRQ
 * @since 2021-02-22
 */
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;
    @Autowired
    private SysRoleMapper sysRoleMapper;
    @Autowired
    private SysRoleMenuMapper sysRoleMenuMapper;
    @Autowired
    private SysMenuMapper sysMenuMapper;

    @Resource
    private SysRoleService sysRoleService;

    @Resource
    IUserMappingService userMappingService;

    private ArrayList<String> expectExt;//头像上传接口后缀名校验

    @Value("${path.userHeadPicFolder}")
    private String userHeadPicFolder;//头像所在文件夹名

    SysUserServiceImpl() {
        expectExt = new ArrayList<>();
        expectExt.add(".jpg");
        expectExt.add(".png");
    }

    @Override
    @DS("#header.instanceid")
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //调用usersMapper方法，根据用户名查询数据库
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        // where username=?
        wrapper.eq("username", username);
        SysUser users = sysUserMapper.selectOne(wrapper);
        //判断
        if (users == null) {//数据库没有用户名，认证失败
            throw new UsernameNotFoundException("用户名不存在！");
        }
        //获取权限列表
        List<String> menus = sysMenuMapper.getMenuFromUserId(users.getId());
        String menu = String.join(",", menus);
        List<GrantedAuthority> auths =
                AuthorityUtils.commaSeparatedStringToAuthorityList(menu);//权限menu
        //从查询数据库返回users对象，得到用户名和密码，返回
        return new User(users.getUsername(), users.getPassword(), auths);
    }

    @Override
    @DS("#header.instanceid")
    public AjaxResponse insertUser(SysUser sysUser, String instanceId) {
        //调用usersMapper方法，根据用户名查询数据库
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        // where username=?
        wrapper.eq("username", sysUser.getUsername());
        SysUser users = sysUserMapper.selectOne(wrapper);
        //判断
        if (users == null) {//数据库没有用户名
            if (StringUtils.isEmpty(sysUser.getUsername())) {
                return AjaxResponse.error(CustomExceptionType.USER_INPUT_ERROR, "用户名不能为空");
            } else if (StringUtils.isEmpty(sysUser.getPassword())) {
                return AjaxResponse.error(CustomExceptionType.USER_INPUT_ERROR, "密码不能为空");
            } else {
                BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
                String encode = encoder.encode(sysUser.getPassword());
                sysUser.setPassword(encode);
                sysUserMapper.insert(sysUser);
                //向主数据库中添加用户映射
                if (!instanceId.equals("master")) {
                    userMappingService.addUserMapping(sysUser.getUsername(), Long.parseLong(instanceId));
                }
                //返回用户id
                HashMap<String, Object> resultMap = new HashMap<>();
                resultMap.put("userId", sysUser.getId());
                return AjaxResponse.success(resultMap);
            }
        }else {
            return AjaxResponse.error("用户名已存在，请重新输入用户名密码");
        }
    }

    /**
     * 用于查询用户id是否有对应用户
     * @param userId 被查询用户id
     * @return 返还是否有对应用户
     */
    @Override
    @DS("#header.instanceid")
    public boolean isUser(long userId) {
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", userId);
        SysUser sysUser = sysUserMapper.selectOne(queryWrapper);
        return sysUser != null;
    }

    /**
     * 通过userId与roleId集合设置对应用户角色
     *
     * @param userId  用户id
     * @param roleSet 角色id
     * @return Map<String, Object> 返还userId，roleId集合
     * @throws CustomException 当用户不存在，角色不存在时抛出该异常
     */
    @Override
    public HashMap<String, Object> setRole(long userId, Set<Long> roleSet) throws CustomException {
        if (!this.isUser(userId)) {
            //非有效用户
            throw new CustomException(CustomExceptionType.USER_NOT_FOUND_ERROR, "找不到该用户");
        }
        if (!sysRoleService.isRole(roleSet)) {
            //传入设置角色集有不存在角色
            throw new CustomException(CustomExceptionType.ROLE_NOT_FOUNT_ERROR, "找不到该角色");
        }
        //获取原有角色集合
        QueryWrapper<SysUserRole> sysUserRoleQueryWrapper = new QueryWrapper<>();
        sysUserRoleQueryWrapper.eq("user_id", userId);
        List<SysUserRole> oldMenuList = sysUserRoleMapper.selectList(sysUserRoleQueryWrapper);
        //将List转化为Set
        Set<Long> oldMenuSet = oldMenuList.stream().map(SysUserRole::getRoleId).collect(Collectors.toSet());
        //计算插入与删除集
        Set<Long> insertSet = new HashSet<>(roleSet);
        Set<Long> removeSet = new HashSet<>(oldMenuSet);
        insertSet.removeAll(oldMenuSet);
        removeSet.removeAll(roleSet);
        //删除移除角色分配
        if (!removeSet.isEmpty()) {
            QueryWrapper<SysUserRole> removeWapper = new QueryWrapper<>();
            for (Long item : removeSet) {
                removeWapper.or().eq("role_id", item);
            }
            sysUserRoleMapper.delete(removeWapper);
        }
        //新增角色分配
        if (!insertSet.isEmpty()) {
            for (Long item : insertSet) {
                sysUserRoleMapper.insert(new SysUserRole(null, userId, item));
            }
        }
        //查询修改后用户角色
        QueryWrapper<SysUserRole> resultWapper = new QueryWrapper<>();
        resultWapper.eq("user_id", userId);
        List<SysUserRole> menuList = sysUserRoleMapper.selectList(resultWapper);
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("userId", userId);
        resultMap.put("roleList", menuList.stream().map(SysUserRole::getRoleId).collect(Collectors.toSet()));
        return resultMap;
    }

    @Override
    public List<SysUser> getUserFromRole(long roleId) throws CustomException {
        if (!sysRoleService.isRole(Collections.singleton(roleId))) {
            //若传入的角色不存在
            throw new CustomException(CustomExceptionType.ROLE_NOT_FOUNT_ERROR, "角色不存在");
        }
        //查询角色-用户记录
        QueryWrapper<SysUserRole> sysUserRoleQueryWrapper = new QueryWrapper<>();
        sysUserRoleQueryWrapper.eq("role_id", roleId);
        List<SysUserRole> sysUserRoleList = sysUserRoleMapper.selectList(sysUserRoleQueryWrapper);
        //查询对应用户
        if (!sysUserRoleList.isEmpty()) {
            QueryWrapper<SysUser> sysUserQueryWrapper = new QueryWrapper<>();
            for (SysUserRole item : sysUserRoleList) {
                sysUserQueryWrapper.or().eq("id", item.getUserId());
            }
            return sysUserMapper.selectList(sysUserQueryWrapper);//返还用户集合
        }
        return null;//该角色无对应用户
    }

    /**
     * 用户头像上传
     *
     * @param userId     用户id
     * @param instanceId 实例id
     * @param file       文件
     * @return 文件url
     * @throws CustomException 当文件后缀不符合要求时抛出
     * @throws IOException     IO异常
     */
    @Override
    public SysUser uploadHeadPic(long userId, String instanceId, MultipartFile file) throws CustomException, IOException {
        //存储文件
        String ext = IO.getExt(file, expectExt);
        String url = "/headPic/" + instanceId + "/" + IO.saveFile(file, ext, "/" + userHeadPicFolder + "/" + instanceId);
        //获取用户信息
        SysUser user = sysUserMapper.selectById(userId);
        //若旧旧头像存在则删除旧头像
        if (!StringUtils.isEmpty(user.getHeadPic())) {
            String fileName = user.getHeadPic().split("/")[3];
            IO.delete("/" + userHeadPicFolder + "/" + instanceId + "/" + fileName);
        }
        //修改用户头像
        user.setHeadPic(url);
        sysUserMapper.updateById(user);
        return user;
    }

    /**
     * 获取用户id
     *
     * @param userId 用户id
     * @return 返还用户实体
     */
    @Override
    public SysUser getInfo(long userId) {
        return sysUserMapper.selectById(userId);
    }

    /**
     * 获取全部特定类型的用户
     *
     * @param type 类型id
     * @return List
     */
    @Override
    public List<SysUser> getAllUser(int type) {
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_type", type);
        return sysUserMapper.selectList(queryWrapper);
    }

    /**
     * 获取特定种类的用户的数量
     *
     * @param type 用户种类
     * @return 特定种类的用户的数量
     */
    @Override
    public int getUserCount(int type) {
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("type", type);
        return sysUserMapper.selectCount(queryWrapper);
    }

    /**
     * 通过用户名从主数据中查询
     *
     * @param username 用户名
     * @return SysUser
     */
    @DS("master")
    @Override
    public SysUser getByUsernameFromMaster(long username) {
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", username);
        return sysUserMapper.selectOne(queryWrapper);
    }
}
